package com.baima46.core;

import cn.hutool.core.util.ReflectUtil;
import com.baima46.annotion.ExcelHeader;
import com.baima46.annotion.ExcelHeaderCol;
import com.baima46.annotion.ExcelParent;
import com.baima46.model.ExcelInfo;
import com.baima46.model.HeaderCell;
import com.baima46.model.SheetInfo;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

/**
 * @Description 表头处理类
 * @Author yuan cong
 * @Date 2020/12/4 0004
 */
public class HeaderHandle {

    /**
     * 将坐标转换为HeaderCell对象集合
     * @param sheetInfo sheet信息
     * @return
     */
    public static List<HeaderCell> getHeaderCellList(SheetInfo sheetInfo) {
        List<List<String>> headerList = null;
        try {
            headerList = getHeaderList(sheetInfo.getDataList(), sheetInfo.getDataClass(), sheetInfo.getGroup());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("解析表头异常！");
        }
        List<List<Boolean>> mergeList = getMergeList(sheetInfo.getDataList(), sheetInfo.getDataClass(), sheetInfo.getGroup());

        List<HeaderCell> headerCellList = getHeaderCellList(headerList, mergeList);

        //保存信息
        sheetInfo.setHeaderCellList(headerCellList);

        return headerCellList;
    }

    /**
     * 将坐标转换为HeaderCell对象集合
     * @param headerList
     * @param mergeList
     * @return
     */
    private static List<HeaderCell> getHeaderCellList(List<List<String>> headerList,List<List<Boolean>> mergeList) {
        List<HeaderCell> headerCellList = new ArrayList<>();

        HashMap<String,int[] > pos = new HashMap<>();
        HashMap<String,Boolean > isAdd = new HashMap<>();

        //列
        for (int i = 0; i < headerList.size(); i++) {
            List<String> row = headerList.get(i);
            //行
            for (int j = 0; j < row.size(); j++) {
                String key = row.get(j);

                //不是第一列，且跟前面一列名称相同
                boolean sameCol = i != 0 && key.equals(headerList.get(i - 1).get(j));
                //不是第一行，且跟前面一行名称相同
                boolean sameRow = j != 0 && key.equals(row.get(j - 1));
                //如果不是第一列，且跟前面一列名称相同, 且前一列 和 当前列是否都需要合并,则最后一列值+1
                if (sameCol && mergeList.get(i - 1).get(j) && mergeList.get(i).get(j)) {
                    int[] ints = pos.get(i - 1 + "," + j);
                    isAdd.put((i - 1) + "," + j,true);

                    //如果前一列 和 当前列都需要合并 才合并
//                    if (mergeList.get(i - 1).get(j) && mergeList.get(i).get(j)){
//                        ints[3] += 1;

                    pos.put(i  + "," + j,new int[]{ints[0],ints[1],ints[2],ints[3] + 1});
//                    }else {
//                        //把前一列添加
//                        headerCellList.add(new HeaderCell(headerList.get(i - 1).get(j),ints[0],ints[1],ints[2],ints[3]));
//                        pos.put(i+","+j,new int[]{j,j,i,i});
//                    }

                    isAdd.put(i+","+j,false);
                }
                //如果不是第一行，且跟前面一行名称相同，则最后一行值+1
                if (sameRow) {
                    int[] ints = pos.get(i + "," + (j-1));
                    isAdd.put(i + "," + (j-1),true);

                    //合并
//                    ints[1] += 1;

                    pos.put(i  + "," + j,new int[]{ints[0],ints[1] + 1,ints[2],ints[3]});
                    isAdd.put(i+","+j,false);

                    //如果前一列没有添加，则添加
                    if(i>0 && !isAdd.get((i - 1) + "," + j)){
                        int[] ints2 = pos.get((i - 1) + "," + j);
                        headerCellList.add(new HeaderCell(headerList.get(i - 1).get(j),ints2[0],ints2[1],ints2[2],ints2[3]));
                        isAdd.put((i - 1) + "," + j,true);
                    }
                }
                //如果既不跟前一列相同，也不跟前一行相同，则是新的表头格
                if (!sameRow && !(sameCol && mergeList.get(i - 1).get(j) && mergeList.get(i).get(j)) ){
                    //如果前一列未添加，则添加
                    if (i>0 && !isAdd.get((i - 1) + "," + j)){
                        int[] ints = pos.get((i - 1) + "," + j);
                        headerCellList.add(new HeaderCell(headerList.get(i - 1).get(j),ints[0],ints[1],ints[2],ints[3]));
                        isAdd.put((i - 1) + "," + j,true);
                    }
                    //如果前一行未添加，则添加
//                    if (j>0 && !isAdd.get(i + "," + (j-1))){
//                        int[] ints = pos.get(i + "," + (j-1));
//                        headerCellList.add(new HeaderCell(row.get(j - 1),ints[0],ints[1],ints[2],ints[3]));
//                        isAdd.put(i + "," + (j-1),true);
//                    }
                    //如果前一行，前一列未添加，则添加
//                    if (j>0 && i>0 && !isAdd.get(i-1 + "," + (j-1))){
//                        int[] ints = pos.get(i-1 + "," + (j-1));
//                        headerCellList.add(new HeaderCell(headerList.get(i - 1).get(j-1),ints[0],ints[1],ints[2],ints[3]));
//                        isAdd.put(i-1 + "," + (j-1),true);
//                    }

                    pos.put(i+","+j,new int[]{j,j,i,i});
                    isAdd.put(i+","+j,false);
                }
            }
        }

        //最后一列
        int i = headerList.size();
        if(i >= 1){
            List<String> lastList = headerList.get(headerList.size() - 1);
            for (int j = 0; j < lastList.size(); j++) {
                //如果前一列未添加，则添加
                if (!isAdd.get((i - 1) + "," + j)){
                    int[] ints = pos.get((i - 1) + "," + j);
                    headerCellList.add(new HeaderCell(headerList.get(i - 1).get(j),ints[0],ints[1],ints[2],ints[3]));
                    isAdd.put((i - 1) + "," + j,true);
                }
            }
        }


//        int[] ints = pos.get(headerList.size() - 1 + "," + (lastList.size() - 1));
//        headerCellList.add(new HeaderCell(lastList.get(lastList.size()-1),ints[0],ints[1],ints[2],ints[3]));

        return headerCellList;
    }


    /**
     * 获取表头是否需要合并的二维数组
     * @param dataList
     * @param dataClass
     * @param groupList
     * @return
     */
    private static List<List<Boolean>> getMergeList(List<?> dataList, Class<?> dataClass, List<String> groupList) {
//        Field[] declaredFields = dataClass.getDeclaredFields();
        List<Field> declaredFields = getFixHeaderFields(dataClass, groupList);

        List<List<Boolean>> headerList = new ArrayList<>();

        //获取表头名称二维数组-固定表头
        //行
        for (Field declaredField : declaredFields) {
            ExcelHeader annotation = declaredField.getAnnotation(ExcelHeader.class);
            if(annotation!=null){
                //组 ---- 因为getFixHeaderFields方法中已经判断，这里不需要再判断
//                String group1 = annotation.group();
//                if (!groupList.isEmpty()){
//                    //传入的组不为空，则匹配组不同的话，则不取标题
//                    if (!groupList.contains(group1)){
//                        continue;
//                    }
//                }

                //整列
                String[] value = annotation.value();
                boolean merge = annotation.mergeRow();

                List<Boolean> merges = new ArrayList();
                for (int j = 0; j < value.length; j++) {
                    merges.add(merge);
                }
                //多行自定义合并
                boolean[] mergeRows = annotation.mergeRows();
                for (int j = 0; j < mergeRows.length; j++) {
                    merges.set(j, mergeRows[j]);
                }

                headerList.add(merges);
            }
        }

        //动态表头
        if(dataList!=null && ! dataList.isEmpty()){
            Object data = dataList.get(0);

            List<Field> dyHeaderFields = getDyHeaderFields(data.getClass());
            for (Field field : dyHeaderFields) {
                //动态表头list
                List<Object> fieldValue = (List<Object>) ReflectUtil.getFieldValue(data, field);
                if (fieldValue==null){
                    continue;
                }
                for (Object o : fieldValue) {
                    Field[] dynamicFields = o.getClass().getDeclaredFields();
                    for (int i = 0; i < dynamicFields.length; i++) {
                        ExcelHeader annotation = dynamicFields[i].getAnnotation(ExcelHeader.class);
                        if(annotation!=null){
                            //组
                            String group1 = annotation.group();
                            if (!groupList.isEmpty()){
                                //传入的组不为空，则匹配组不同的话，则不取标题
                                if (!groupList.contains(group1)){
                                    continue;
                                }
                            }

                            //整列
                            String[] value = annotation.value();
                            boolean merge = annotation.mergeRow();

                            List<Boolean> merges = new ArrayList();
                            for (int j = 0; j < value.length; j++) {
                                merges.add(merge);
                            }
                            //多行自定义合并
                            boolean[] mergeRows = annotation.mergeRows();
                            for (int j = 0; j < mergeRows.length; j++) {
                                merges.set(j, mergeRows[j]);
                            }

                            headerList.add(merges);
                        }
                    }
                }
            }
        }

        return headerList;
    }

    /**
     * 获取表头名称二维数组
     * @param dataClass
     * @return
     */
    private static List<List<String>> getHeaderList(List<?> dataList, Class<?> dataClass, List<String> groupList) throws InvocationTargetException, IllegalAccessException {
        //数据类的属性
        Field[] declaredFields = dataClass.getDeclaredFields();

        //数据类的父类属性
        Class<?> superclass = dataClass.getSuperclass();
        Field[] superclassDeclaredFields = superclass.getDeclaredFields();
        //继承父类属性的位置
        ExcelParent excelParent = dataClass.getAnnotation(ExcelParent.class);
        int position = 1;
        if (excelParent!=null){
            position = excelParent.value();
        }


        //结果
        List<List<String>> headerList = new ArrayList<>();

        //如果需要父类属性加在前面
        if (position==1){
            addHeader(headerList, dataList, superclassDeclaredFields, groupList);
        }

        //获取表头名称二维数组-固定表头
        addHeader(headerList, dataList, declaredFields, groupList);

        //如果需要父类属性加在后面
        if (position==2){
            addHeader(headerList, dataList, superclassDeclaredFields, groupList);
        }

        //动态表头
        if(dataList!=null && ! dataList.isEmpty()){
            Object data = dataList.get(0);

            List<Field> dyHeaderFields = getDyHeaderFields(data.getClass());
            for (Field field : dyHeaderFields) {
                //动态表头list
                List<Object> fieldValue = (List<Object>) ReflectUtil.getFieldValue(data, field);
                if (fieldValue==null){
                    continue;
                }
                for (Object o : fieldValue) {
                    Field[] dynamicFields = o.getClass().getDeclaredFields();
                    for (int i = 0; i < dynamicFields.length; i++) {
                        ExcelHeader annotation = dynamicFields[i].getAnnotation(ExcelHeader.class);
                        if(annotation!=null){
                            //组
                            String group1 = annotation.group();
                            if (!groupList.isEmpty()){
                                //传入的组不为空，则匹配组不同的话，则不取标题
                                if (!groupList.contains(group1)){
                                    continue;
                                }
                            }

                            //整列
                            String[] value = annotation.value();

                            //如果需要替换
                            String[] colField = annotation.colField();
                            for (int j = 0; j < colField.length; j++) {
                                Object fieldValue2 = ReflectUtil.getFieldValue(o, colField[j]);
                                if (fieldValue2!=null && !"".equals(fieldValue2)){
                                    value[j] = String.valueOf(fieldValue2);
                                }
                            }

                            //如果需要方法返回值替换表头名
                            String[] colMethod = annotation.colMethod();
                            for (int j = 0; j < colMethod.length; j++) {
                                Method method = ReflectUtil.getPublicMethod(o.getClass(), colMethod[j]);
                                if (method!=null){
                                    Object methodValue = method.invoke(o);
                                    if (methodValue!=null && !"".equals(methodValue)){
                                        value[j] = String.valueOf(methodValue);
                                    }
                                }
                            }

                            headerList.add(Arrays.asList(value));
                        }
                    }
                }
            }
        }

        return headerList;
    }

    /**
     * 添加头信息
     * @param headerList
     * @param superclassDeclaredFields
     */
    private static void addHeader(List<List<String>> headerList, List<?> dataList, Field[] superclassDeclaredFields, List<String> groupList) throws InvocationTargetException, IllegalAccessException {
        //获取表头名称二维数组-固定表头
        //行
        for (int i = 0; i < superclassDeclaredFields.length; i++) {
            ExcelHeader annotation = superclassDeclaredFields[i].getAnnotation(ExcelHeader.class);
            if(annotation!=null){
                //组
                String group1 = annotation.group();
                if (!groupList.isEmpty()){
                    //传入的组不为空，则匹配组不同的话，则不取标题
                    if (!groupList.contains(group1)){
                        continue;
                    }
                }

                //列
                String[] value = annotation.value();

                //如果需要替换
                if (!dataList.isEmpty()){
                    String[] colField = annotation.colField();
                    for (int j = 0; j < colField.length; j++) {
                        Object fieldValue2 = ReflectUtil.getFieldValue(dataList.get(0), colField[j]);
                        if (fieldValue2!=null && !"".equals(fieldValue2)){
                            value[j] = String.valueOf(fieldValue2);
                        }
                    }
                }

                //如果需要方法返回值替换表头名
                String[] colMethod = annotation.colMethod();
                for (int j = 0; j < colMethod.length; j++) {
                    Method method = ReflectUtil.getPublicMethod(dataList.get(0).getClass(), colMethod[j]);
                    if (method!=null){
                        Object methodValue = method.invoke(dataList.get(0));
                        if (methodValue!=null && !"".equals(methodValue)){
                            value[j] = String.valueOf(methodValue);
                        }
                    }
                }

                headerList.add(Arrays.asList(value));
            }
        }
    }

    /**
     * 获取固定表头列
     * @param clazz
     * @return
     */
    private static List<Field> getFixHeaderFields(Class<?> clazz, List<String> group) {
        //数据类的属性
        Field[] declaredFields = clazz.getDeclaredFields();

        //数据类的父类属性
        Class<?> superclass = clazz.getSuperclass();
        Field[] superclassDeclaredFields = superclass.getDeclaredFields();
        //继承父类属性的位置
        ExcelParent excelParent = clazz.getAnnotation(ExcelParent.class);
        int position = 1;
        if (excelParent!=null){
            position = excelParent.value();
        }

        //先预先判断字段数量大小
        int size = declaredFields.length + superclassDeclaredFields.length;
        size = Math.max(size, 16);
        //结果字段集合
        List<Field> headerList = new ArrayList<>(size);

        //如果需要父类属性加在前面
        if (position==1){
            addHeader(headerList, superclassDeclaredFields, group);
        }

        //获取表头名称二维数组-固定表头
        addHeader(headerList, declaredFields, group);

        //如果需要父类属性加在后面
        if (position==2){
            addHeader(headerList, superclassDeclaredFields, group);
        }

        return headerList;
    }

    /**
     * 获取动态表头列
     * @param clazz
     * @return
     */
    private static List<Field> getDyHeaderFields(Class<?> clazz) {
        Field[] declaredFields = clazz.getDeclaredFields();

        //数据类的父类属性
        Class<?> superclass = clazz.getSuperclass();
        Field[] superclassDeclaredFields = superclass.getDeclaredFields();
        //继承父类属性的位置
        ExcelParent excelParent = clazz.getAnnotation(ExcelParent.class);
        int position = 1;
        if (excelParent!=null){
            position = excelParent.value();
        }

        List<Field> fieldNames = new ArrayList<>();

        //如果需要父类属性加在前面
        if (position==1){
            addField(fieldNames, superclassDeclaredFields);
        }

        //添加属性
        addField(fieldNames, declaredFields);

        //如果需要父类属性加在后面
        if (position==2){
            addField(fieldNames, superclassDeclaredFields);
        }

        return fieldNames;
    }

    /**
     * 添加动态集合列字段
     * @param fieldNames
     * @param declaredFields
     */
    private static void addField(List<Field> fieldNames, Field[] declaredFields){
        for (int i = 0; i < declaredFields.length; i++) {
            ExcelHeaderCol annotation = declaredFields[i].getAnnotation(ExcelHeaderCol.class);
            if(annotation!=null && "java.util.List".equals(declaredFields[i].getType().getName())){
                fieldNames.add(declaredFields[i]);
            }
        }
    }









    /**
     * 获取表头列属性
     * @param sheetInfo sheet信息
     * @return
     */
    private static List<Field> getHeaderFields(SheetInfo sheetInfo) {
        //数据类的属性
        Field[] declaredFields = sheetInfo.getDataClass().getDeclaredFields();

        //数据类的父类属性
        Class<?> superclass = sheetInfo.getDataClass().getSuperclass();
        Field[] superclassDeclaredFields = superclass.getDeclaredFields();
        //继承父类属性的位置
        ExcelParent excelParent = sheetInfo.getDataClass().getAnnotation(ExcelParent.class);
        int position = 1;
        if (excelParent!=null){
            position = excelParent.value();
        }

        //先预先判断字段数量大小
        int size = declaredFields.length + superclassDeclaredFields.length;
        size = Math.max(size, 16);
        //结果字段集合
        List<Field> headerList = new ArrayList<>(size);



        return headerList;
    }

    /**
     * 获取表头列属性
     * @param clazz 要解析的类
     * @param group 要导出的组
     * @return
     */
    private static List<Field> getHeaderFields(Class<?> clazz, List<String> group) {
        //数据类的属性
        Field[] declaredFields = clazz.getDeclaredFields();

        //数据类的父类属性
        Class<?> superclass = clazz.getSuperclass();
        Field[] superclassDeclaredFields = superclass.getDeclaredFields();
        //继承父类属性的位置
        ExcelParent excelParent = clazz.getAnnotation(ExcelParent.class);
        int position = 1;
        if (excelParent!=null){
            position = excelParent.value();
        }

        //先预先判断字段数量大小
        int size = declaredFields.length + superclassDeclaredFields.length;
        size = Math.max(size, 16);
        //结果字段集合
        List<Field> headerList = new ArrayList<>(size);

        //如果需要父类属性加在前面
        if (position==1){
            addHeader(headerList, superclassDeclaredFields, group);
        }

        //获取表头名称二维数组-固定表头
        addHeader(headerList, declaredFields, group);

        //如果需要父类属性加在后面
        if (position==2){
            addHeader(headerList, superclassDeclaredFields, group);
        }

        //动态表头



        return headerList;
    }

    /**
     * 添加头信息
     * @param headerList
     * @param classDeclaredFields
     */
    private static void addHeader(List<Field> headerList, Field[] classDeclaredFields, List<String> groupList) {
        //获取表头字段数组-固定表头
        //行
        for (int i = 0; i < classDeclaredFields.length; i++) {
            ExcelHeader annotation = classDeclaredFields[i].getAnnotation(ExcelHeader.class);
            if(annotation!=null){
                //组
                String group1 = annotation.group();
                if (!groupList.isEmpty()){
                    //传入的组不为空，则匹配组不同的话，则不取标题
                    if (!groupList.contains(group1)){
                        continue;
                    }
                }

                headerList.add(classDeclaredFields[i]);
            }
        }
    }

    /**
     * 获取动态表头列
     * @param clazz
     * @return
     */
    private static List<Field> getDyHeaderFields(Class<?> clazz, List<String> groupList) {
        Field[] declaredFields = clazz.getDeclaredFields();

        //动态列
        List<Field> dyFieldNames = new ArrayList<>();

        //添加动态集合属性
        addField(dyFieldNames, declaredFields);
        //还没实现。。。。

        return dyFieldNames;
    }

}
